#ifndef TextView_First
#define TextView_First
#ifdef __GNUG__
#pragma interface
#endif

#include "StaticTView.h"

class FindDialog;
class TypingCommand;
class RegularExp;
class TextRangeSelector;
class ExtendTextRangeSelector;
class Text;
class TypingTimer;

extern const int cMaxBatchedIns;    // maximum number of batched inserts

struct SelPoint {
	int ch;         // char number of a selection point
	int line;       // line number of a selection
	Point viewp;    // position in view coordinates
	bool IsEqual(const SelPoint &s2);
};

void SwapSelPoints(SelPoint &p1, SelPoint &p2);

//---- TextView ----------------------------------------------------------------

class TextView: public StaticTextView {
friend TextRangeSelector;
friend ExtendTextRangeSelector;
friend TypingTimer;
public:
	MetaDef(TextView);

	TextView(
		EvtHandler *eh, Rectangle r, Text *t,
		bool wrap= cWordWrap,
		TextViewFlags= eTextViewDefault,
		Point border= gBorder,
		TViewAlign ta= eTViewLeft,
		int id= cIdNone
	);  // if contentRect.extent.y is set to cVariableSize
		// extent.y is adapted to extent of largest text line

	~TextView();
	void InitNew();

	void Draw(Rectangle);
	void Invert(int from, Point fp, int to, Point tp);
	void HighlightSelection(HighlightState hs);
	void RepairAll();

	//---- controller methods
	bool KbdFocus(bool in);
	void SetKeyMap(int *map);
	Command *DoLeftButtonDownCommand(Point, Token, int);
	Command *DoKeyCommand(int, Token);
	Command *DoCursorKeyCommand(EvtCursorDir, Token);

	//---- menu handling
	static Menu *MakeMenu(int menuId);
	void DoSetupMenu(Menu *m);
	void SetupEditMenu(Menu *m);
	void SetupSizeMenu(Menu *m);
	void SetupFontMenu(Menu *m);
	void SetupViewMenu(Menu *m);
	void SetupCharStyleMenu(Menu *m);
	void SetupFormatMenu(Menu *m);
	Command *DoMenuCommand(int);

	void SetStopChars(char *stopChars);
		// define in a string a list of characters that should not be
		// batched in DoKeyCommand. Has to be used when DoKeyCommand
		// is overridden to intercept carriage returns for instance
	const char *GetStopChars();

	Command *InsertText(Text *insert);
	Command *InsertString(const byte *insert, int len= -1);

	void Enable(bool b= TRUE, bool redraw= TRUE);
	GrCursor GetCursor(Point);

	//---- selection ----
	void InvalidateSelection();
	void SetSelection(int s= 0, int e= cMaxInt, bool redraw= TRUE);
	void ClearSelection(bool redraw= TRUE);
	void SetDragAndDrop(bool on);
	void GetSelection(int *s, int *e= 0);
	void SelectionAsString(byte*, int max);
	Text *SelectionAsText();
	Rectangle SelectionRect();
	Rectangle BoundingRect(int from, int to);
	void RevealSelection();
	bool InTextSelector()
		{ return inTextSelector; }
	virtual void Home();
	virtual void Bottom();
	bool Caret();
	bool AnySelection();
	virtual void SelectAll(bool redraw= TRUE);
	virtual void DrawCaret(Point p, int line, HighlightState);
	void ShowSelection(bool redraw= TRUE, bool show= TRUE);
	bool CanShowSelection();
	void ShowLine(int line, int delay= 0);

	//---- clipboard --------------------
	bool HasSelection();
	bool IsReadOnly();
	Command *PasteData(Data*);

	//---- editing and screen update
	virtual void Cut();
	virtual void DelChar(int n=1);
	virtual bool DeleteRequest(int from, int to);
		// called before deleting the text in the range from, to
		// a return value of FALSE indicates a veto, and the text will not be
		// deleted
	virtual void Copy(Text *save);
	virtual void Paste(Text *insert);
	Text *SetText(Text *, bool scroll= cRevealTop);     // returns old text
	void SetString(byte *str, int len= -1);
	CharStyle *GetCharStyle();

	void SetReadOnly(bool);
	bool GetReadOnly();

	//---- searching
	virtual bool SelectRegExpr(RegularExp *rex, bool forward= TRUE);

	//----- Command Notification
	void FlushBatchedChars();
	void DoneTyping();  // notify typeing command
	void TypingDeleted(TypingCommand *typing);
	virtual TypingCommand *MakeTypingCommand(int cmdNo, char *name);

	//----- change notification from the text object
	void DoObserve(int, int part, void*, Object *op);
	bool PrintOnWhenObserving(Object *from);

	//---- activation passivation ----------------------------------------------
	IStream& ReadFrom(IStream&);

protected:
	bool updateSelection;

	//---- selection
	SelPoint start, end;            // selection range

	void NormSelection();
		// normalize selection, establisch start < end
	void PrivSetSelection(int s, int e, bool redraw= TRUE);
	void PrivSetSelection(SelPoint s, SelPoint e, bool redraw= TRUE);
	void Init();
	bool Writeable();
	virtual int CursorPos(int ch, int line, EvtCursorDir d, Point);

private:
	bool inTextSelector;
	bool enabled, active;
	char *stopChars; // these characters wont be batched during DoKeyCommand              // if DoKeyCommand is overriden
	TypingCommand *typing; // current typeing command object
	FindDialog *findChange;
	TypingTimer *timer;
};

//---- inlines -----------------------------------------------------------------

inline bool SelPoint::IsEqual(const SelPoint &s2)
{
	return (bool) (ch == s2.ch);
}

inline bool TextView::Caret()
{
	return (bool) (start.ch == end.ch);
}

inline bool TextView::AnySelection()
{
	return (bool) (start.ch != -1);
}

inline bool TextView::CanShowSelection()
{
	return enabled && !gPrinting;
}

inline void TextView::GetSelection(int *s, int *e)
{
	if (s)
		*s= start.ch;
	if (e)
		*e= end.ch;
}

inline const char *TextView::GetStopChars()
{
	return stopChars;
}

inline bool TextView::Writeable()
{
	return (bool) (!TestFlag(eTextViewReadOnly) && Enabled());
}

#endif
